//
//  MyUDP.m
//  MyScoketTest
//
//  Created by wilson_chen on 2009/12/30.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <CFNetwork/CFSocketStream.h>
#include <arpa/inet.h>

#import "MyUDP.h"
#import "proto.h"

#define mPort 30003
#define mServerIP @"122.147.6.109"

NSString * const TCPServerErrorDomain = @"TCPServerErrorDomain";

@interface MyUDP ()
@property(assign) uint16_t port;
@end

@implementation MyUDP
@synthesize port=_port;

- (id)init {
    return self;
}

- (void)dealloc {
	if (sockobj > 0)
		shutdown(sockobj,SHUT_RDWR);
    [self stop];
    [super dealloc];
}

// This function is called by CFSocket when a new connection comes in.
// We gather some data here, and convert the function call to a method
// invocation on TCPServer.
static void UDPServerAcceptCallBack(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) {
    MyUDP *server = (MyUDP *)info;
    if (kCFSocketAcceptCallBack == type) { 
        // for an AcceptCallBack, the data parameter is a pointer to a CFSocketNativeHandle
        CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data;
        uint8_t name[SOCK_MAXADDRLEN];
        socklen_t namelen = sizeof(name);
        NSData *peer = nil;
        if (0 == getpeername(nativeSocketHandle, (struct sockaddr *)name, &namelen)) {
            peer = [NSData dataWithBytes:name length:namelen];
        }
        CFReadStreamRef readStream = NULL;
		CFWriteStreamRef writeStream = NULL;
        CFStreamCreatePairWithSocket(kCFAllocatorDefault, nativeSocketHandle, &readStream, &writeStream);
        if (readStream && writeStream) {
            CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
            CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
            //[server handleNewConnectionFromAddress:peer inputStream:(NSInputStream *)readStream outputStream:(NSOutputStream *)writeStream];
        } else {
            // on any failure, need to destroy the CFSocketNativeHandle 
            // since we are not going to use it any more
            close(nativeSocketHandle);
        }
        if (readStream) CFRelease(readStream);
        if (writeStream) CFRelease(writeStream);
    }
}

- (BOOL)start:(NSError **)error {
    
	//sockobj = socket(AF_INET, SOCK_DGRAM, 0);
	
	//if (sockobj < 0)
	//	return NO;
	
	CFSocketContext socketCtxt = {0, self, NULL, NULL, NULL};
    _ipv4socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_DGRAM, IPPROTO_UDP, kCFSocketDataCallBack, (CFSocketCallBack)&UDPServerAcceptCallBack, &socketCtxt);
	
    //if (NULL == _ipv4socket) {
    //    if (error) *error = [[NSError alloc] initWithDomain:TCPServerErrorDomain code:kTCPServerNoSocketsAvailable userInfo:nil];
    //    if (_ipv4socket) CFRelease(_ipv4socket);
    //    _ipv4socket = NULL;
    //    return NO;
    //}
	
	
    int yes = 1;
    setsockopt(CFSocketGetNative(_ipv4socket), SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
	
    //// set up the IPv4 endpoint; use port 0, so the kernel will choose an arbitrary port for us, which will be advertised using Bonjour
    //struct sockaddr_in addr4;
    //memset(&addr4, 0, sizeof(addr4));
    //addr4.sin_len = sizeof(addr4);
    //addr4.sin_family = AF_INET;
    //addr4.sin_port = 0;
    //addr4.sin_addr.s_addr = htonl(INADDR_ANY);
    //NSData *address4 = [NSData dataWithBytes:&addr4 length:sizeof(addr4)];
	
    //if (kCFSocketSuccess != CFSocketSetAddress(_ipv4socket, (CFDataRef)address4)) {
    //    if (error) *error = [[NSError alloc] initWithDomain:TCPServerErrorDomain code:kTCPServerCouldNotBindToIPv4Address userInfo:nil];
    //    if (_ipv4socket) CFRelease(_ipv4socket);
    //    _ipv4socket = NULL;
    //    return NO;
    //}
    
	//// now that the binding was successful, we get the port number 
	//// -- we will need it for the NSNetService
	//NSData *addr = [(NSData *)CFSocketCopyAddress(_ipv4socket) autorelease];
	//memcpy(&addr4, [addr bytes], [addr length]);
	//self.port = ntohs(addr4.sin_port);
	
	
    //// set up the run loop sources for the sockets
    //CFRunLoopRef cfrl = CFRunLoopGetCurrent();
    //CFRunLoopSourceRef source4 = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _ipv4socket, 0);
    //CFRunLoopAddSource(cfrl, source4, kCFRunLoopCommonModes);
    //CFRelease(source4);
	
	
    return YES;
}

- (BOOL)stop {
    //[self disableBonjour];
	
	if (_ipv4socket) {
		CFSocketInvalidate(_ipv4socket);
		CFRelease(_ipv4socket);
		_ipv4socket = NULL;
	}
	
	
    return YES;
}

- (int)senddata
{
	//struct sockaddr *saddr;
	
	int ret;
	char *buf;
	
    struct sockaddr_in addr4;
    memset(&addr4, 0, sizeof(addr4));
    addr4.sin_len = sizeof(addr4);
    addr4.sin_family = AF_INET;
    addr4.sin_port = htons(30003);
    //addr4.sin_addr.s_addr = htonl(INADDR_ANY);
    addr4.sin_addr.s_addr = inet_addr((char*)@"122.147.6.109");
    NSData *address4 = [NSData dataWithBytes:&addr4 length:sizeof(addr4)];
	
	//if (addr4.sin_addr.s_addr == INADDR_NONE)
	//	return -1;
	
	buf = (char*)malloc(sizeof(PKTHeader) + sizeof(LoginMessage_t));
	
	memset(buf, 0, sizeof(PKTHeader) + sizeof(LoginMessage_t));
	
	PKTHeader *header = (PKTHeader *)buf;
	LoginMessage_t *user = (LoginMessage_t *)(buf + sizeof(PKTHeader));
	
	header->verId = P2P_VERID;
	header->nid = MSGTYPE_HPREQ;
	header->data_length = htons(sizeof(LoginMessage_t));
	
	sprintf(user->username, (char*)@"%@", @"AAAA0001");
	sprintf(user->password, (char*)@"%@", @"12345678");
	
	NSData *data = [NSData dataWithBytes:buf length:sizeof(PKTHeader)+sizeof(LoginMessage_t)];
	
	ret = CFSocketSendData(_ipv4socket, (CFDataRef)address4, (CFDataRef)data, (CFTimeInterval)1000);
	
	//ret = sendto(sockobj, buf, sizeof(PKTHeader)+sizeof(LoginMessage_t), 0, (const struct sockaddr *)&addr4, sizeof(addr4));
	
	return ret;
	//inet_aton();
}

@end
